package com.sxt.jt808.handler;

import static com.sxt.jt808.commons.JT808Const.TERNIMAL_MSG_AUTH;
import static com.sxt.jt808.commons.JT808Const.TERNIMAL_MSG_HEARTBEAT;
import static com.sxt.jt808.commons.JT808Const.TERNIMAL_MSG_LOCATION;
import static com.sxt.jt808.commons.JT808Const.TERNIMAL_MSG_LOGOUT;
import static com.sxt.jt808.commons.JT808Const.TERNIMAL_MSG_REGISTER;

import java.util.Date;

import org.springframework.stereotype.Component;

import com.sxt.jt808.dto.AuthMsg;
import com.sxt.jt808.dto.BaseMsg;
import com.sxt.jt808.dto.HeartBeatMsg;
import com.sxt.jt808.dto.Jt808Msg;
import com.sxt.jt808.dto.LocationMsg;
import com.sxt.jt808.dto.RegisterMsg;

import io.netty.buffer.ByteBuf;
//import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

/**
 * netty服务器的监听 处理器
 * 
 * @Author: 罗林
 * @Date: 2019-05-15
 * @Description: 业务handler基础方法
 * @Version: 1.0
 */
@Slf4j
@Component
public class IOHandler extends ChannelInboundHandlerAdapter {

	private int UNCONNECT_NUM = 0;

	/**
	 * @函数的名称:channelRead
	 * @目的/功能:从通道中读取数据
	 * @输入参数:ChannelHandlerContext 通道，Object 客户端发来的数据
	 * @返回值:无
	 * @throws Exception
	 * @作者:罗林
	 * @日期:2019.11.13
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) {
		Jt808Msg jt808Msg = (Jt808Msg) msg;
		// 处理客户端消息
		this.processClientMsg(jt808Msg);
	}

	/**
	 * @函数的名称:exceptionCaught
	 * @目的/功能:发生异常时，处理函数
	 * @输入参数:ChannelHandlerContext 通道，cause 异常信息
	 * @返回值:无
	 * @作者:罗林
	 * @日期:2019.11.13
	 */
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		ctx.close();
		log.error("发生异常:{" + cause.getMessage() + "}");
		// 出现异常时，可以发送或者记录相关日志信息，之后，直接断开该链接，并重新登录请求，建立通道
	}

	/**
	 * 客户端连接会触发
	 * 
	 * @函数的名称:channelActive
	 * @目的/功能:当客户端主动链接服务端的链接后，这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
	 * @输入参数:ChannelHandlerContext 通道
	 * @返回值:无
	 * @作者:罗林
	 * @日期:2019.11.13
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		// 通知您已经链接上客户端
//		String str = "您已经开启与服务端链接" + " " + new Date() + " " + ctx.channel().localAddress();
//		ByteBuf buf = Unpooled.buffer(str.getBytes().length);
//		buf.writeBytes(str.getBytes("UTF-8"));
//		ctx.writeAndFlush(buf);
	}

	/**
	 * @函数的名称:channelActive
	 * @目的/功能:当客户端主动断开服务端的链接后，这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
	 * @输入参数:ChannelHandlerContext 通道
	 * @返回值:无
	 * @作者:罗林
	 * @日期:2019.11.13
	 */
	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		System.out.println(ctx.channel().localAddress().toString() + " channelInactive");
	}

	/**
	 * @函数的名称:userEventTriggered
	 * @目的/功能:用户自定义触发事件
	 * @输入参数:ChannelHandlerContext 通道
	 * @返回值:无
	 * @作者:罗林
	 * @日期:2019.11.13
	 */
	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
//		if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) {
//			if (UNCONNECT_NUM >= 4) {
//				System.err.println("client connect status is disconnect.");
//				ctx.close();
//				// 此处当重启次数达到4次之后，关闭此链接后，清除服务端相关的记录信息
//				return;
//			}
//			IdleStateEvent event = (IdleStateEvent) evt;
//			// 超时关闭channel
//			switch (event.state()) {
//			case WRITER_IDLE:
//				System.out.println("send ping to client---date=" + new Date());
//				// 发送心跳
//				ctx.writeAndFlush("ping\n");
//				UNCONNECT_NUM++;
//				System.err.println("writer_idle over. and UNCONNECT_NUM=" + UNCONNECT_NUM);
//				break;
//			case READER_IDLE:
//				// 读取服务端消息超时时，直接断开该链接，并重新登录请求，建立通道
//				System.err.println("reader_idle over.");
//
//			case ALL_IDLE:
//				// 读取服务端消息超时时，直接断开该链接，并重新登录请求，建立通道
//				System.err.println("all_idle over.");
//			default:
//				break;
//			}
//		}
	}

	/*
	 * channelReadComplete
	 * 
	 * channel 通道 Read 读取 Complete 完成
	 * 
	 * 在通道读取完成后会在这个方法里通知，对应可以做刷新操作 ctx.flush()
	 * 
	 */
	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//        System.out.println(sb.toString());
		ctx.flush();
	}

	/**
	 * 
	 * 处理业务逻辑
	 * 
	 * @param packageData
	 * 
	 */
	private void processClientMsg(Jt808Msg jt808Msg) {
		// 取2字节的内容，返回转换后的short类型
		short msgId = jt808Msg.getMsgHeader().getMsgId();
		ByteBuf msgBodyByteBuf = jt808Msg.getMsgBodyByteBuf();
		//
		BaseMsg msg = null;
		switch (msgId) {
		case TERNIMAL_MSG_HEARTBEAT:// 心跳
			 msg = new HeartBeatMsg(msgBodyByteBuf);
			break;
		case TERNIMAL_MSG_LOCATION:// 位置
			 msg = new LocationMsg(msgBodyByteBuf);
			break;
		case TERNIMAL_MSG_REGISTER:// 注册
			 msg = new RegisterMsg(msgBodyByteBuf);
			break;
		case TERNIMAL_MSG_AUTH:// 鉴权
			 msg = new AuthMsg(msgBodyByteBuf);
			break;
		case TERNIMAL_MSG_LOGOUT:// 注销
			// msg = new LogOutMsg(msgBodyByteBuf);
			break;
		default:
			// msg = new Jt808Msg(msgBodyByteBuf);
			break;
		}
		if(msg!=null) {
			msg.parseBody();
			System.out.println(msg.toString());
		}
	}
}
